{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "from torch.utils.data import Dataset\n",
    "from torch.utils.data import DataLoader\n",
    "from torch.optim import SGD\n",
    "from torch.optim.lr_scheduler import LambdaLR\n",
    "import pandas as pd\n",
    "import os"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>category</th>\n",
       "      <th>currency</th>\n",
       "      <th>state</th>\n",
       "      <th>country</th>\n",
       "      <th>pledged</th>\n",
       "      <th>goal</th>\n",
       "      <th>year</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1533.95</td>\n",
       "      <td>2015</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>2421.0</td>\n",
       "      <td>30000.00</td>\n",
       "      <td>2017</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>220.0</td>\n",
       "      <td>45000.00</td>\n",
       "      <td>2013</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>2</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1.0</td>\n",
       "      <td>5000.00</td>\n",
       "      <td>2012</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>1283.0</td>\n",
       "      <td>19500.00</td>\n",
       "      <td>2015</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   category  currency  state  country  pledged      goal  year\n",
       "0         0         0      0        0      0.0   1533.95  2015\n",
       "1         1         1      0        1   2421.0  30000.00  2017\n",
       "2         1         1      0        1    220.0  45000.00  2013\n",
       "3         2         1      0        1      1.0   5000.00  2012\n",
       "4         1         1      1        1   1283.0  19500.00  2015"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data = pd.read_csv('final_dataset.csv')\n",
    "\n",
    "data = data.drop(columns=['origin_id'],axis=1)\n",
    "\n",
    "data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# randomly split data into training data and test data\n",
    "# training data : test data = 9 : 1\n",
    "\n",
    "data = data.sample(frac=1.0)\n",
    "\n",
    "cut_idx = int(round(0.1 * data.shape[0]))\n",
    "\n",
    "test_data, train_data = data.iloc[:cut_idx], data.iloc[cut_idx:]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class CrowdfundingDataset(Dataset):\n",
    "    def __init__(self, data):\n",
    "        super(CrowdfundingDataset, self).__init__()\n",
    "        \n",
    "        inputs = data[['category', 'currency', 'country', 'pledged', 'goal', 'year']]\n",
    "        labels = data[['state']]\n",
    "        \n",
    "        # Min-Max Normalization\n",
    "        inputs_norm = (inputs - inputs.min()) / (inputs.max() - inputs.min())\n",
    "        \n",
    "        self.x_data = inputs_norm.values\n",
    "        self.y_data = labels.values\n",
    "        \n",
    "        self.length = len(self.y_data)\n",
    "    \n",
    "    def __getitem__(self, index):\n",
    "        return self.x_data[index], self.y_data[index]\n",
    "    \n",
    "    def __len__(self):\n",
    "        return self.length\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class NeuralNetwork_1Hidden(nn.Module):\n",
    "\n",
    "    def __init__(self, in_dim, out_dim):\n",
    "        super(NeuralNetwork_1Hidden, self).__init__()\n",
    "        \n",
    "        n_hidden_1 = 16\n",
    "        \n",
    "        self.layers = nn.Sequential(\n",
    "            nn.Linear(in_dim, n_hidden_1),\n",
    "            nn.ReLU(True),\n",
    "            nn.Linear(n_hidden_1, out_dim)\n",
    "        )\n",
    "\n",
    "    def forward(self, input):\n",
    "        output = self.layers(input)\n",
    "        return output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class NeuralNetwork_2Hiddens(nn.Module):\n",
    "\n",
    "    def __init__(self, in_dim, out_dim):\n",
    "        super(NeuralNetwork_2Hiddens, self).__init__()\n",
    "        \n",
    "        n_hidden_1 = 16\n",
    "        n_hidden_2 = 32\n",
    "        \n",
    "        self.layers = nn.Sequential(\n",
    "            nn.Linear(in_dim, n_hidden_1),\n",
    "            nn.ReLU(True),\n",
    "            nn.Linear(n_hidden_1, n_hidden_2),\n",
    "            nn.ReLU(True),\n",
    "            nn.Linear(n_hidden_2, out_dim)\n",
    "        )\n",
    "\n",
    "    def forward(self, input):\n",
    "        output = self.layers(input)\n",
    "        return output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "class NeuralNetwork_3Hiddens(nn.Module):\n",
    "\n",
    "    def __init__(self, in_dim, out_dim):\n",
    "        super(NeuralNetwork_3Hiddens, self).__init__()\n",
    "        \n",
    "        n_hidden_1 = 16\n",
    "        n_hidden_2 = 32\n",
    "        n_hidden_3 = 16\n",
    "        \n",
    "        self.layers = nn.Sequential(\n",
    "            nn.Linear(in_dim, n_hidden_1),\n",
    "            nn.ReLU(True),\n",
    "            nn.Linear(n_hidden_1, n_hidden_2),\n",
    "            nn.ReLU(True),\n",
    "            nn.Linear(n_hidden_2, n_hidden_3),\n",
    "            nn.ReLU(True),\n",
    "            nn.Linear(n_hidden_3, out_dim)\n",
    "        )\n",
    "\n",
    "    def forward(self, input):\n",
    "        output = self.layers(input)\n",
    "        return output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Hyperparameter\n",
    "batch_size = 256\n",
    "num_epoches = 40\n",
    "learning_rate = 1e-1\n",
    "momentum = 0.8\n",
    "weight_decay = 1e-5\n",
    "power = 0.9"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# dataset\n",
    "train_dataset = CrowdfundingDataset(train_data)\n",
    "test_dataset = CrowdfundingDataset(test_data)\n",
    "\n",
    "# dataloader\n",
    "train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\n",
    "test_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "# model\n",
    "# model = NeuralNetwork_1Hidden(6, 5)\n",
    "# model = NeuralNetwork_2Hiddens(6, 5)\n",
    "model = NeuralNetwork_3Hiddens(6, 5)\n",
    "\n",
    "# Loss & Optimizer & Scheduler\n",
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate, momentum=momentum, weight_decay=weight_decay)\n",
    "lr_lambda = lambda epoch: 1.0 - pow((epoch / num_epoches), power)\n",
    "scheduler = LambdaLR(optimizer, lr_lambda)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "# train\n",
    "\n",
    "model.train()\n",
    "\n",
    "for epoch in range(num_epoches):\n",
    "    \n",
    "    running_loss = 0.0\n",
    "    running_correct = 0\n",
    "    \n",
    "    for i, data in enumerate(train_dataloader):\n",
    "        inputs, labels = data\n",
    "        \n",
    "        inputs = inputs.to(torch.float32)\n",
    "        labels = labels.to(torch.long)\n",
    "        labels = labels.squeeze(1)\n",
    "\n",
    "        # forward propagation\n",
    "        outputs = model(inputs)\n",
    "        loss = criterion(outputs, labels)\n",
    "        \n",
    "        with torch.no_grad():\n",
    "            running_loss += loss.item()\n",
    "            cls_pred = torch.softmax(outputs, dim=1)\n",
    "            cls_out = torch.argmax(cls_pred, dim=1)\n",
    "            running_correct += (cls_out == labels).sum()\n",
    "\n",
    "        # backward propagation\n",
    "        optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "    \n",
    "    running_loss /= len(train_dataset)\n",
    "    running_acc = float(running_correct) / len(train_dataset)\n",
    "    \n",
    "    results = open('./Models/NeuralNetworks/NeuralNetwork_3Hiddens.txt', \"a+\")\n",
    "    \n",
    "    print('Finish {} epoch, Loss: {:.6f}, Acc: {:.6f}'.format(epoch + 1, running_loss, running_acc), \n",
    "          file=results)\n",
    "    \n",
    "    results.close()\n",
    "    \n",
    "    scheduler.step()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "# test\n",
    "\n",
    "model.eval()\n",
    "\n",
    "with torch.no_grad():\n",
    "    correct = 0\n",
    "    for data in test_dataloader:\n",
    "        inputs, labels = data\n",
    "\n",
    "        inputs = inputs.to(torch.float32)\n",
    "        labels = labels.to(torch.long)\n",
    "        labels = labels.squeeze(1)\n",
    "\n",
    "        outputs = model(inputs)\n",
    "        cls_pred = torch.softmax(outputs, dim=1)\n",
    "        cls_out = torch.argmax(cls_pred, dim=1)\n",
    "        correct += (cls_out == labels).sum()\n",
    "\n",
    "    acc = float(correct) / len(test_dataset)\n",
    "    results = open('./Models/NeuralNetworks/NeuralNetwork_3Hiddens.txt', \"a+\")\n",
    "    results.write('\\n')\n",
    "    print('Test Acc = {:.6f}'.format(acc), file=results)\n",
    "    results.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "results = open('./Models/NeuralNetworks/NeuralNetwork_3Hiddens.txt', \"a+\")\n",
    "results.write('\\n')\n",
    "for parameters in model.parameters():\n",
    "    print(parameters, file=results)\n",
    "results.close()\n",
    "\n",
    "torch.save(model.state_dict(), './Models/NeuralNetworks/NeuralNetwork_3Hiddens.pth')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
